package com.jjiang.bbmall.order.config;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

@Configuration
public class MyRabbitConfig {

    RabbitTemplate rabbitTemplate;

    @Primary
    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        this.rabbitTemplate = rabbitTemplate;
        rabbitTemplate.setMessageConverter(messageConverter());
        initRabbitTemplate();
        return rabbitTemplate;
    }

    /**
     * 序列化机制使用JSON
     *
     * @return
     */
    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }

    /**
     * 初始化rabbitTemplate，实现可靠传输
     * <p>
     * 设置发送端可靠机制
     * 设置确认抵达Broker
     * 1. spring.rabbitmq.publisher-returns=true
     * 2. 设置确认回调
     * 设置抵达队列回调
     * 1. spring.rabbitmq.publisher-returns=true
     * 2. spring.rabbitmq.template.mandatory=true
     * <p>
     * 设置接收端可靠机制
     * 1. spring.rabbitmq.listener.simple.acknowledge-mode=manual
     * 2. 需要手动调用函数进行ack确认，如果不确认，则消息会存储在队列中，不会丢失。
     *
     * @initRabbitTemplate：MyRabbitConfig创建完成后就调用该函数
     */
//    @PostConstruct
    public void initRabbitTemplate() {
        // 设置确认回调
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            /**
             * 只要消息能抵达Broker，则回调用此回调
             * @param correlationData 当前消息的唯一关联消息（唯一id）
             * @param b 消息是否收到
             * @param s 失败的原因
             */
            @Override
            public void confirm(CorrelationData correlationData, boolean b, String s) {
                // 服务器收到了
                System.out.println(correlationData + ":" + b + ":" + s);
            }
        });

        // 设置抵达队列的回调，消息未抵达队列时会调用
        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            /**
             *
             * @param message 投递失败的消息的信息
             * @param i 回复码
             * @param s 回复的文本内容
             * @param s1 消息时发送给哪个交换机的
             * @param s2 当时消息的路由键
             */
            @Override
            public void returnedMessage(Message message, int i, String s, String s1, String s2) {
                // 报错了，应该修改数据库中消息的状态
                System.out.println(message + ":" + i + ":" + s + ":" + s1 + ":" + s2);
            }
        });
    }
}
